package com.qiall.gateway.controller;

import com.alibaba.fastjson.JSON;
import com.google.gson.annotations.JsonAdapter;
import com.qiall.assertutil.Assert;
import com.qiall.common.exception.BusinessException;
import com.qiall.common.exception.BusinessResult;
import com.qiall.common.exception.ResultCode;
import com.qiall.common.request.BaseAuthDTO;
import com.qiall.common.request.BaseRequest;
import com.qiall.gateway.controller.request.ApiRequest;
import com.qiall.gateway.controller.request.ApiResponse;

import com.qiall.gateway.controller.request.OuterApiRequest;
import com.qiall.gateway.data.entity.ApiInfo;
import com.qiall.gateway.data.entity.ApiRoleMap;
import com.qiall.gateway.data.mapper.ApiInfoMapper;
import com.qiall.gateway.data.mapper.ApiRoleMapMapper;
import com.qiall.gateway.service.DubboServiceService;
import com.qiall.gateway.service.InvokeDubboService;
import com.qiall.gateway.service.dubborpc.DubboRpc;
import com.qiall.oms.ability.FindDubboService;
import com.qiall.oms.ability.request.DubboInfoDTO;
import com.qiall.oms.ability.request.ReportDubboRequest;
import com.qiall.user.ability.entity.UserInfoDTO;
import com.qiall.user.ability.service.user.UserService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@RestController
@RequestMapping
public class ApiController {
    @Autowired
    private DubboServiceService dubboServiceService;

    @Autowired
    private ApiInfoMapper apiInfoMapper;

    @Autowired
    private ApiRoleMapMapper apiRoleMapMapper;

    @Autowired
    private InvokeDubboService invokeDubboService;

    @DubboReference
    private UserService userService;

    @DubboReference(version = "${dubbo.provider.version}")
    private FindDubboService findDubbService;

    @PostMapping("/innerServiceInvoke")
    public BusinessResult<ApiResponse> service(@RequestBody ApiRequest request) {
        BusinessResult<DubboInfoDTO> result = findDubbService.findBuddoServiceByService(request.getRequestService());
        DubboInfoDTO dto = result.getBody();
        List<ReportDubboRequest.MethodInfo> methods = JSON.parseArray(dto.getMethods(), ReportDubboRequest.MethodInfo.class);
        ReportDubboRequest.MethodInfo methodInfo = methods.stream().filter(x -> x.getMethodName().equals(request.getRequestMethod())).collect(Collectors.toList()).get(0);
        Object[] params = getObjects(JSON.parseArray(request.getRequestData(), String.class), methodInfo.getParamTypes());
        Object object = dubboRpc.genericInvoke(dto.getServiceName(), methodInfo.getMethodName(), methodInfo.getParamTypes(), params);
        ApiResponse apiResponse = new ApiResponse();
        apiResponse.setResponseData(object);
        return BusinessResult.success(apiResponse);
    }

    @Autowired
    private DubboRpc dubboRpc;

    @PostMapping("/service/{path}")
    public BusinessResult<ApiResponse> service(@PathVariable("path") String path, @RequestBody OuterApiRequest outerApiRequest) {
        ApiInfo apiInfo = apiInfoMapper.selectByApiPath(path);
        // 权限校验
        check(apiInfo, outerApiRequest.getRequestData());
        // 服务调用

        BusinessResult<DubboInfoDTO> dubboInfoDTOBusinessResult = findDubbService.findBuddoServiceByService(apiInfo.getServiceName());
        DubboInfoDTO dto = dubboInfoDTOBusinessResult.getBody();
        List<ReportDubboRequest.MethodInfo> methods = JSON.parseArray(dto.getMethods(), ReportDubboRequest.MethodInfo.class);
        List<ReportDubboRequest.MethodInfo> methodInfos = methods.stream().filter(x -> x.getMethodName().equals(apiInfo.getMethodName())).collect(Collectors.toList());
        Assert.notNull(methodInfos, "函数不存在");
        ReportDubboRequest.MethodInfo methodInfo = methodInfos.get(0);
        Object[] params = getObjects(JSON.parseArray(outerApiRequest.getRequestData(), String.class), methodInfo.getParamTypes());
        Object object = dubboRpc.genericInvoke(dto.getServiceName(), methodInfo.getMethodName(), methodInfo.getParamTypes(), params);
        ApiResponse apiResponse = new ApiResponse();
        apiResponse.setResponseData(object);
        return BusinessResult.success(apiResponse);
    }


    private void check(ApiInfo apiInfo, String requestData) {
        List<ApiRoleMap> apiRoleMap = apiRoleMapMapper.selectByApiId(apiInfo.getId());
        // 没有配置不需要校验
        if (CollectionUtils.isEmpty(apiRoleMap)) {
            return;
        }
        List<BaseRequest> baseAuthDTO = JSON.parseArray(requestData, BaseRequest.class);
        String accessToken = baseAuthDTO.get(0).getAccessToken();
        if (StringUtils.isBlank(accessToken)) {
            throw new BusinessException(ResultCode.USER_NOT_LOGIN);
        }
        UserInfoDTO userInfoDTO = userService.getUserInfoByAuthCode(baseAuthDTO.get(0)).getBody();
        Integer roleId = userInfoDTO.getRoleId();
        Set<Integer> roleIds = apiRoleMap.stream().map(x -> x.getRoleId()).collect(Collectors.toSet());
        if (!roleIds.contains(roleId)) {
            throw new BusinessException(ResultCode.USER_AUTH_FAIL);
        }
    }

    private Object[] getObjects(List<String> args, List<String> parameterTypes) {
        Object[] objects = new Object[args.size()];
        for (int i = 0; i < args.size(); i++) {
            Class<?> classTmp = invokeDubboService.getDubboClass(parameterTypes.get(i));
            Object obj = JSON.parseObject(args.get(i), classTmp);
            objects[i] = obj;
        }
        return objects;
    }

    @RequestMapping("/thirdPard")
    public void thirdPartAppMessage() {

    }

}
